package com.pangu.core.engine.game.task.poker;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.cache2k.expiry.ValueWithExpiryTime;

import com.pangu.core.BMDataContext;
import com.pangu.core.cache.CacheHelper;
import com.pangu.core.engine.game.ActionTaskUtils;
import com.pangu.core.engine.game.BeiMiGameTask;
import com.pangu.core.engine.game.ChessGameEngine;
import com.pangu.core.engine.game.model.PlayerRecordDezhou;
import com.pangu.core.engine.game.model.Summary;
import com.pangu.core.engine.game.model.SummaryPlayer;
import com.pangu.core.engine.game.task.AbstractTask;
import com.pangu.util.PokerUtilsPro;
import com.pangu.util.disruptor.DisruptorHandler;
import com.pangu.util.rules.model.GameStatus;
import com.pangu.util.rules.model.NiuniuPosition;
import com.pangu.util.rules.model.PokerBoard;
import com.pangu.web.model.GameRoom;
import com.pangu.web.model.PlayUserClient;
import com.pangu.web.service.repository.es.PlayUserClientESRepository;
import com.pangu.web.service.repository.es.PlayerRecordDezhouESRepository;
import com.pangu.web.service.repository.jpa.PlayUserClientRepository;
import com.pangu.web.service.repository.jpa.PlayerRecordDezhouRepository;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: PokerEndTask
 * @Description: 结算
 * @author 老王
 * @date 2018年4月25日 下午1:27:15
 *
 */
@Slf4j
public class PokerEndTask extends AbstractTask implements ValueWithExpiryTime, BeiMiGameTask {

	private long timer;
	private GameRoom gameRoom = null;
	private String orgi;

	public PokerEndTask(long timer, GameRoom gameRoom, String orgi) {
		super();
		this.timer = timer;
		this.gameRoom = gameRoom;
		this.orgi = orgi;
	}

	@Override
	public long getCacheExpiryTime() {
		return System.currentTimeMillis() + timer * 1000; // 5秒后执行
	}

	@Override
	public void execute() {
		long begin = System.currentTimeMillis();
		// 1.获取牌局
		PokerBoard board = (PokerBoard) CacheHelper.getBoardCacheBean().getCacheObject(gameRoom.getId(),
				gameRoom.getOrgi());
		List<PlayUserClient> plays = CacheHelper.getGamePlayerCacheBean().getCacheObject(gameRoom.getId(), orgi);
		// 2.结算
		Summary sm = this.saveRecord(board, plays);
		// 3.发送结算数据
		super.sendEvent(sm.getCommand(), sm, gameRoom);//
		// 4.更新奖金池
		this.updatePool(sm);
		// 2.清除已经托管的用户以及ai钱数不够的用户
		BMDataContext.getContext().getBean(ChessGameEngine.class).leaveRoom(gameRoom.getId(), orgi);
		// 完成，清除相关数据
		BMDataContext.getContext().getBean(ChessGameEngine.class).finished(gameRoom, plays,
				BMDataContext.GameTypeEnum.DEZHOU.toString());
		BMDataContext.getContext().getBean(ChessGameEngine.class).updateTop(gameRoom.getId(), orgi);
		log.info("准备进行下一局，休息10秒钟·······················");
		GameStatus status = new GameStatus(BMDataContext.GameStatusEnum.END.toString(), "游戏结束，等待10秒钟进行下一局");
		ActionTaskUtils.sendEvent(BMDataContext.BEIMI_GAMESTATUS_EVENT, status, gameRoom);
		// 7.end 持久化
		CacheHelper.getGameStatusCacheBean().put(gameRoom.getRoomid(), status, gameRoom.getOrgi());
		// 8.驱动下一局
		CacheHelper.getExpireCache().put(gameRoom.getRoomid(),
				new PokerDealTask(BMDataContext.GAME_NEXT_TIME, gameRoom, gameRoom.getOrgi()));
		long end = System.currentTimeMillis();
		log.info("结算消耗时间：{}ms", end - begin);
	}

	/**
	 * @Description :更新奖金池
	 * @author 老王
	 * 
	 */
	private void updatePool(Summary sm) {
		double total = 0;
		List<SummaryPlayer> cord = sm.getPlayers();
		for (SummaryPlayer summaryPlayer : cord) {
			if (0 == summaryPlayer.getRatio()) {
				total = total + summaryPlayer.getBalance();
			}
		}
		BMDataContext.getContext().getBean(ChessGameEngine.class)
				.updateGameBonusPool(BMDataContext.GameTypeEnum.DEZHOU.toString().toLowerCase(), total, orgi);
	}

	/*
	 * 结算保存数据，从下注记录里面去取
	 */
	public Summary saveRecord(PokerBoard board, List<PlayUserClient> plays) {
		if (plays == null) {// 玩家是允许为空的。
			return null;
		}
		// 得到胜利的玩家；
		NiuniuPosition[] p = PokerUtilsPro.Compare(board.getNiuniuPosition(), board.getLasthands());
		if (p == null) {
			log.info("怎么可能赢家是空的呢");
			return null;
		}
		List<NiuniuPosition> winner = PokerUtilsPro.getWiner(p);
		// 首先要得到所有赢家的下注记录
		// 得到其他人的下注记录
		// 每一局每一个人只记录一条下注记录（汇总的）
		List<PlayerRecordDezhou> record = this.dealPlayerRecord(plays, p);
		// 得到所有闲家的金额
		// 得到所有庄家的金额
		return this.getSummary(record, winner, plays, p, board.getId());
	}

	/**
	 * @Description :
	 * @author 老王
	 *         <p>
	 *         首先， 我想单独拿出胜利者的下注记录。当然也可以不拿出来，直接做计算
	 *         <p>
	 * @ FIXME 验证计算double的准确性
	 * <P>
	 * 
	 */
	public Summary getSummary(List<PlayerRecordDezhou> plays, List<NiuniuPosition> winner, List<PlayUserClient> players,
			NiuniuPosition[] p, String boardId) {
		List<PlayerRecordDezhou> winner_recoard = new ArrayList<>();
		for (NiuniuPosition niuniuPosition : winner) {
			for (PlayerRecordDezhou pl : plays) {
				if (pl.getPlayerId().equals(niuniuPosition.getPlayer())) {
					winner_recoard.add(pl);
					break;
				}
			}
		}
		double total_coin = this.countMoney(plays);// 总金额
		plays.removeAll(winner_recoard);// 得到loser
		double winner_coin = this.countMoney(winner_recoard);// 赢家下注金额
		double loser_coin = total_coin - winner_coin;// 输的金额
		if (loser_coin <= winner_coin) {// 输的小于赢家下注金额，所以不要退款，赢家按比例瓜分
			// 计算输的人
			for (PlayerRecordDezhou playerRecordDezhou : plays) {
				playerRecordDezhou.setWinLoseCoin(-playerRecordDezhou.getCoin());
				this.saveRecord(playerRecordDezhou, players);
			}
			// 计算赢家收入
			for (PlayerRecordDezhou playerRecordDezhou : winner_recoard) {
				BigDecimal bg = new BigDecimal((playerRecordDezhou.getCoin() / winner_coin * loser_coin));
				playerRecordDezhou.setWinLoseCoin(bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
				this.saveRecord(playerRecordDezhou, players);
			}
		} else {// 这个时候就是减去赢家下注，然后剩下的退还给其他下注的人
			// 计算赢家收入
			for (PlayerRecordDezhou playerRecordDezhou : winner_recoard) {
				playerRecordDezhou.setWinLoseCoin(playerRecordDezhou.getCoin());
				this.saveRecord(playerRecordDezhou, players);
			}
			// 计算输的人
			for (PlayerRecordDezhou playerRecordDezhou : plays) {
				BigDecimal bg = new BigDecimal(-playerRecordDezhou.getCoin() / loser_coin * winner_coin);
				playerRecordDezhou.setWinLoseCoin(bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
				this.saveRecord(playerRecordDezhou, players);
			}
		}
		// 构造返回结果
		Summary s = new Summary();
		s.setCommand(BMDataContext.BEIMI_SETTLEMENT_EVENT);
		s.setBoard(boardId);
		s.setGame(gameRoom.getId());
		List<SummaryPlayer> sp = new ArrayList<>();
		plays.addAll(winner_recoard);
		for (PlayerRecordDezhou playerRecordDezhou : plays) {
			SummaryPlayer ss = new SummaryPlayer();
			ss.setBalance(playerRecordDezhou.getWinLoseCoin());
			ss.setUserid(playerRecordDezhou.getPlayerId());
			ss.setWin(true);
			for (PlayUserClient playUserClient : players) {
				if (playUserClient.getId().equals(playerRecordDezhou.getPlayerId())) {
					ss.setScore(playUserClient.getGoldcoins());
					// 偷懒一次，有时间可以fix一下
					ss.setRatio(BMDataContext.PlayerTypeEnum.AI.toString().toLowerCase()
							.equals(playUserClient.getPlayertype()) ? 0 : 1);
				}
			}
			sp.add(ss);
		}
		s.setPlayers(sp);
		return s;

	}

	private void saveRecord(PlayerRecordDezhou playerRecord, List<PlayUserClient> players) {
		// 持久化下注记录
		DisruptorHandler.published(playerRecord,
				BMDataContext.getContext().getBean(PlayerRecordDezhouESRepository.class),
				BMDataContext.getContext().getBean(PlayerRecordDezhouRepository.class));
		// 扣钱
		for (PlayUserClient playUserClient : players) {
			if (playUserClient.getId().equals(playerRecord.getPlayerId())) {
				playUserClient.setGoldcoins(playUserClient.getGoldcoins() + playerRecord.getWinLoseCoin());
				CacheHelper.getGamePlayerCacheBean().put(playUserClient.getId(), playUserClient, orgi); // 持久化用户数据
				DisruptorHandler.published(playUserClient,
						BMDataContext.getContext().getBean(PlayUserClientESRepository.class),
						BMDataContext.getContext().getBean(PlayUserClientRepository.class));
				CacheHelper.getApiUserCacheBean().put(playUserClient.getId(), playUserClient, orgi); // 持久化用户数据
				break;
			}
		}

	}

	/**
	 * @Description :计算金币总数
	 * @author 老王
	 */
	private double countMoney(List<PlayerRecordDezhou> plays) {
		double result = 0;
		for (PlayerRecordDezhou playerRecordDezhou : plays) {
			result = result + playerRecordDezhou.getCoin();
		}
		return result;
	}

	/**
	 * @Description :处理下注记录
	 * @author 老王
	 *         <p>
	 *         我希望结算的时候数据库里面只存一条下注记录，所以结算的时候何必每个人的下注记录
	 *         <p>
	 *         这样最后结算的时候也好计算
	 *         <P>
	 * 
	 */
	private List<PlayerRecordDezhou> dealPlayerRecord(List<PlayUserClient> plays, NiuniuPosition[] p) {
		List<PlayerRecordDezhou> result = new ArrayList<PlayerRecordDezhou>();
		for (PlayUserClient playUserClient : plays) {
			List<PlayerRecordDezhou> record = (List<PlayerRecordDezhou>) CacheHelper.getGameRecordDeZhouCacheBean()
					.getCacheObject(playUserClient.getId(), orgi);
			if (record == null) {
				continue;// 然后解决吃瓜群众的问题
			}
			double total = 0;
			for (PlayerRecordDezhou playerRecord : record) {
				total = total + playerRecord.getCoin();
			}
			PlayerRecordDezhou temp = record.get(0);
			temp.setCoin(total);
			for (NiuniuPosition np : p) {
				if (temp.getPlayerId().equals(np.getPlayer())) {
					temp.setCards(np.getCards_string());
				}
			}
			result.add(temp);
		}
		return result;
	}

}
